<?php

/*
 * Manager/InstructionManager.php
 */

namespace RHX\Model\Manager;

use Zend\Db\Adapter\Adapter;
use RHX\Model\Object\InstructionPaie;
use RHX\Model\Object\Prime;
use RHX\Model\Object\XRules;
use RHX\Helper\RHDateTime;

class InstructionManager {

    /**
     *
     * @var Adapter
     */
    protected $adapter = null;

    /**
     * Constructeur
     * 
     * @param \Zend\Db\Adapter\Adapter $adapter
     */
    public function __construct(Adapter $adapter) {
	$this->adapter = $adapter;
    }

    /**
     * Adapteur de base de données
     * 
     * @return Adapter
     */
    public function getAdapter() {
	return $this->adapter;
    }

    /**
     * Contenu tableau des instructions
     * 
     * @param mixed $post
     * @return array tableau des instructions de paie
     */
    public function loadPlanningContent($post) {
	$what = $this->whatAction($post);
	switch ($what['action']) {
	    case InstructionPaie::CREATE:
		return $this->createInstructionPaie($post);
	    case InstructionPaie::VIEW:
		return $this->viewInstructionPaie($post, $what['id']);
	    default:
		return $this->createInstructionPaie($post);
	}
    }

    /**
     * Détermine l'action a entreprendre
     * 
     * @param \Zend\Stdlib\Parameters $post
     * @return array
     */
    private function whatAction($post) {
	//return array('action' => InstructionPaie::CREATE, 'id' => 0);
	$tableInstructionGroup	 = new \RHX\Model\Table\InstructionPaieGroupTable($this->getAdapter());
	$instructions		 = $tableInstructionGroup->getAllByPeriodeAndSite($post->periode, $post->site);
	if ($instructions->count() > 0) {        
	    return array('action' => InstructionPaie::VIEW, 'id' => $instructions->current()->id);
	}
    // var_dump('create'); 
	return array('action' => InstructionPaie::CREATE, 'id' => 0);
    }

    /**
     * Récupération des données en provenance des plannings semaines
     *
     * \Zend\Stdlib\Parameters $post
     * @return array tableau des instructions de paie
     */
    public function createInstructionPaie($post) {
	// manager 
	$empManager = new \RHX\Model\Manager\EmployeManager($this->getAdapter());

	// table planning
	$tablePlanning	 = new \RHX\Model\Table\PlanningSemaineTable($this->getAdapter());
	$tablePeriode	 = new \RHX\Model\Table\PeriodeTable($this->getAdapter());
	$tableSite	 = new \RHX\Model\Table\SiteTable($this->getAdapter());
	$tableEmploye	 = new \RHX\Model\Table\EmployeTable($this->getAdapter());
	$periode	 = $tablePeriode->get($post->periode);
	try{
	    $site		 = $tableSite->get($post->site);
	}catch(\Exception $ex){
	    $site		 = new \RHX\Model\Object\Site(array('id' => -1, 'libelle' => 'Total COJEAN'));
	}

	//$employes	 = $tableEmploye->getEmployesBySiteEx($site->id, 'poste_rang ASC');
	$employes = $empManager->getEmployesByPeriode($post->site, $post->periode, 'poste_rang asc, prenom asc');

        // instruction group
        $group = $this->saveInstructionGroup($post);
        
	// instruction de paie
	$instructions	 = array();
	$calculator	 = new \RHX\Model\Object\XCalculator($this->getAdapter());
	foreach ($employes as $e) {
	    $instruction			 = new InstructionPaie($this->getAdapter());
	    $plannings			 = $this->transformToArray($tablePlanning->getPlanningsByDateRange($e->matricule, $periode->debut, $periode->fin));
	    $data				 = $calculator->calculInstructionPaie($plannings, $e->matricule);
	    $instruction->fill($data);
	    // Affectation
            $instruction->group = $group;
	    $instruction->matricule		 = $e->matricule;
	    $salaire = $calculator->calculSalaireBrute($instruction, $plannings, $periode->debut);
	    $instruction->salaire_brute	 = $salaire['salaire'];
	    $instruction->mode_calcul = $salaire['mode'];
	    //var_dump($instruction);

	    // instructions de paie
	    $instructions[] = $instruction;
	}
        
	//$instructions = $this->saveInstructions($instructions, $group);        
	$post->set('action', InstructionPaie::CREATE);

	return $instructions;
    }

    /**
     * Sauvegarder tous les insructions de paie
     * 
     * @param array $instructions
     * @param int $group
     * @return array
     */
    private function saveInstructions($instructions, $group) {
	$tableInstruction	 = new \RHX\Model\Table\InstructionPaieTable($this->getAdapter());
	$instr			 = array();
	foreach ($instructions as $i) {
	    $i->group	 = $group;
	    $i->id		 = $tableInstruction->save($i);
	    $instr[]	 = $i;
	}
	return $instr;
    }

    /**
     * Sauvegarder le groupe d'instruction
     * 
     * @param \Zend\Stdlib\Parameters $post
     * @return int
     */
    private function saveInstructionGroup($post) {
	$tableGroup		 = new \RHX\Model\Table\InstructionPaieGroupTable($this->getAdapter());
	$group			 = new \RHX\Model\Object\InstructionPaieGroup($this->getAdapter());
	$periode		 = $this->getPeriode($post->periode);
	$site			 = $this->getSite($post->site);
	$group->libelle		 = "Instruction de Paie pour la période $periode->libelle pour le site $site->libelle ";
	$group->periode_id	 = $periode->id;
	$group->site_id		 = $site->id;
	return (int) $tableGroup->save($group);
    }

    /**
     * Récupération des données enregistré des instructions de paie
     *
     * @param mixed $post
     * @param int $id
     * @return array
     */
    public function viewInstructionPaie($post, $id) {
	$tableInstruction	 = new \RHX\Model\Table\InstructionPaieTable($this->getAdapter());
	$tablePlanning		 = new \RHX\Model\Table\PlanningSemaineTable($this->getAdapter());
	$calculator		 = new \RHX\Model\Object\XCalculator($this->getAdapter());
	$empManager		 = new EmployeManager($this->getAdapter());
	$employes		 = $empManager->getEmployesByPeriode($post->site, $post->periode, 'poste_rang asc, prenom asc');
	$instructions		 = array();
	$periode		 = $this->getPeriode($post->periode);
        $calculator	 = new \RHX\Model\Object\XCalculator($this->getAdapter());
	foreach ($employes as $e) {
	    $inst = $tableInstruction->getOneByMatricule($e->matricule, $id);
            //var_dump($inst);
	    if (is_null($inst)) {
		$inst		 = new InstructionPaie($this->getAdapter());
		$inst->matricule = $e->matricule;
		$inst->id	 = -1;
		$inst->group = $id;
	    }
	    $plannings	 = $this->transformToArray($tablePlanning->getPlanningsByDateRange($e->matricule, $periode->debut, $periode->fin));
            $isSaved = $inst->id > 0 ;
	    $data		 = $calculator->calculInstructionPaie($plannings, $e->matricule, $isSaved);
            $inst->fill($data);
            $salaire = $calculator->calculSalaireBrute($inst, $plannings, $periode->debut);
            $inst->salaire_brute	 = $salaire['salaire'];
	    $inst->mode_calcul = $salaire['mode'];
	    $instructions[]	 = $inst;
	}
	$post->set('action', InstructionPaie::VIEW);
	
	return $instructions;
    }

    /**
     * Période
     * 
     * @param type $periodeId
     * @return \RHX\Model\Object\Periode
     */
    public function getPeriode($periodeId) {
	$tablePeriode = new \RHX\Model\Table\PeriodeTable($this->getAdapter());
	return $tablePeriode->get($periodeId);
    }

    /**
     * Préparation des données
     * 
     * @param \Zend\Stdlib\Parameters $post
     * @return \RHX\Model\Object\InstructionPaie
     */
    public function prepareData($post) {
	$instr	 = $post->instr;
	$data	 = array();
	foreach ($instr as $i) {
	    $data[] = new InstructionPaie($this->getAdapter(), $i);
	}
	//var_dump($data);
	return $data;
    }

    /**
     * Titre
     * 
     * @param \Zend\Stdlib\Parameters $post
     * @return array
     */
    public function prepareTitle($post) {
	$periode = $this->getPeriode($post->periode);
	$site	 = $this->getSite($post->site);
	return array(
	    'periode'	 => $this->getPeriodeName($periode) . $this->getPeriodeYear($periode),
	    'site'		 => \RHX\Helper\Number::getSiteLibelle($site->libelle),
	    'number'	 => $this->getSiteNumber($site),
	);
    }

    /**
     * Site
     * 
     * @param int $siteId
     * @return \RHX\Model\Object\Site
     */
    public function getSite($siteId) {
	$tableSite = new \RHX\Model\Table\SiteTable($this->getAdapter());
	try{
	    $site = $tableSite->get($siteId);
	}catch(\Exception $ex){
	    $site = new \RHX\Model\Object\Site(array('id' => -1, 'libelle' => 'Total COJEAN'));
	}
	return $site;
    }

    /**
     * Liste des primes
     * 
     * @param int $type
     * @return Prime
     */
    public function getPrimeList($type = Prime::CP) {
	$tablePrime	 = new \RHX\Model\Table\PrimeTable($this->getAdapter());
	$primeList	 = $tablePrime->select(function(\Zend\Db\Sql\Select $select)use($type) {
	    $where = new \Zend\Db\Sql\Where();
	    $where->equalTo('is_cp', $type);
	    $select->where($where);
	    $select->order('id DESC');
	});
	return $this->convertToArray($primeList);
    }

    /**
     * Conversion en Tableau
     * *
     * @param Prime $list
     * @return array
     */
    public function convertToArray($list) {
	$array = array();
	foreach ($list as $elt) {
	    $array[$elt->id] = $elt->libelle;
	}
	return $array;
    }

    /**
     * Sélection d'une prime
     * 
     * @param int $primeId
     * @return Prime
     */
    public function getPrime($primeId) {
	$tablePrime = new \RHX\Model\Table\PrimeTable($this->getAdapter());
	return $tablePrime->select(array('id' => $primeId))
			->current();
    }

    /**
     * Mutuelle
     * 
     * @param string $libelle
     * @return \RHX\Model\Object\Mutuelle
     */
    public function getMutuelleReference($libelle = 'AM/Cadre') {
	$tableMutuelle	 = new \RHX\Model\Table\MutuelleTable($this->getAdapter());
	$mutuelle	 = $tableMutuelle->select(function(\Zend\Db\Sql\Select $select)use($libelle) {
		    $where = new \Zend\Db\Sql\Where();
		    $where->literal("libelle LIKE '%$libelle%'");
		    $select->where($where);
		})->current();
	return $mutuelle;
    }

    /**
     * Comparaison des mutuelles
     * 
     * @param \RHX\Model\Object\Mutuelle $mutuelle1
     * @param \RHX\Model\Object\Mutuelle $mutuelle2
     * @return boolean
     */
    public function isMutuelleEgale(\RHX\Model\Object\Mutuelle $mutuelle1, \RHX\Model\Object\Mutuelle $mutuelle2) {
	return ($mutuelle1->id == $mutuelle2->id) && ($mutuelle1->libelle == $mutuelle2->libelle);
    }

    /**
     * Année de la période
     * 
     * @param \RHX\Model\Object\Periode $periode
     * @param int $nb
     * @return string
     */
    public function getPeriodeYear(\RHX\Model\Object\Periode $periode, $nb = 2) {
	$fin = new \RHX\Helper\RHDateTime($periode->fin);
	return $fin->date('y');
    }

    /**
     * Mois de la période
     * 
     * @param \RHX\Model\Object\Periode $periode
     * @return string
     */
    public function getPeriodeName(\RHX\Model\Object\Periode $periode) {
	list($libelle, $year) = sscanf($periode->libelle, "%s %d");
	return $libelle;
    }

    /**
     * Numéro du site
     * 
     * @param \RHX\Model\Object\Site $site
     * @param boolean $print
     * @return int
     */
    public function getSiteNumber(\RHX\Model\Object\Site $site, $print = true) {
	list($nb, $label) = sscanf($site->libelle, "%d - %s");
	return ($print) ? (((int) $nb < 10) ? '0' . $nb : $nb) : (int) $nb;
    }

    /**
     * 
     * @param \RHX\Model\Object\Periode $periode
     * @param \RHX\Model\Object\Site $site
     */
    public function getInstructions(\RHX\Model\Object\Periode $periode, \RHX\Model\Object\Site $site) {
	//
    }

    /**
     * Calcul salaire
     * 
     * @param int $instrId
     * @return real
     */
    public function calculSalaire($instrId) {
	$paie	 = $this->getInstruction($instrId);
	$employe = $paie->getEmploye();
	$excel	 = new ExcelManager($this->getAdapter());
	return $excel->salaireBrute($paie, $employe->getTaux());
    }

    /**
     * Instruction de paie d'un employé
     * 
     * @param int $id
     * @return InstructionPaie
     */
    public function getInstruction($id) {
	$tablePaie	 = new \RHX\Model\Table\InstructionPaieTable($this->getAdapter());
	$paie		 = $tablePaie->get($id);
	return $paie;
    }
    
    /**
     * Insertion d'une nouvelle instruction de paie dans la base de données
     * 
     * @param \Zend\Stdlib\Parameters $post
     * @return \RHX\Model\Object\InstructionPaie
     */
    public function insert($post){
	$tablePaie = new \RHX\Model\Table\InstructionPaieTable($this->getAdapter());
	$tablePlanning = new \RHX\Model\Table\PlanningSemaineTable($this->getAdapter());
	$tablePeriode = new \RHX\Model\Table\PeriodeTable($this->getAdapter());
	$calculator = new \RHX\Model\Object\XCalculator($this->getAdapter());
	$periode = $tablePeriode->get($post->periode);
	$plannings = $tablePlanning->getPlanningsByDateRange($post->matricule, $periode->debut, $periode->fin);
	$data = $calculator->calculInstructionPaie($plannings, $post->matricule);
	$instruction = new InstructionPaie($this->getAdapter());
	$instruction->fill($data);
	$name = $post->name;
	$instruction->matricule = $post->matricule;
	$instruction->group = $post->group;
	$instruction->$name = $post->value;
	$instruction->id = $tablePaie->save($instruction);
	return $instruction;
    }

    /**
     * Liste des sites pour affichage dans les instructions de paie
     * 
     * @param array $params
     * @return string
     */
    public function siteListe($params = array()){
	$all = isset($params['all']) ? $params['all'] : true;
	$synthese = isset($params['synthese']) ? $params['synthese'] : true;
	$tableSite = new \RHX\Model\Table\SiteTable($this->getAdapter());
	$siteList = $tableSite->getSelectList(array('Total COJEAN'));
	//$siteList[-1] = "Total COJEAN";
	return $siteList;
    }
    
     /**
     * Récupérer une Instruction de paie pour un employe
     *
     * @param int $matricule
     * @param int $group
     * @return null|InstructionPaie
     */
    public function getByMatriculeGroup($matricule, $group) {
	$tablePaie = new \RHX\Model\Table\InstructionPaieTable($this->getAdapter());
        
	return $tablePaie->getOneByMatricule($matricule, $group);
    }
    
    /**
     * Récupération des heures théoriques
     * 
     * @param int $matricule
     * @param \RHX\Model\Object\Periode $periode
     * @param boolean $isFloat
     * @return float
     */
    public function getES($matricule, $periode){
	$plannings = $this->transformToArray($this->getPlannings($matricule, $periode->debut, $periode->fin));
	$stats = $this->getStats($plannings);
	$infoFirst = $this->getFirstWorkWeek($stats);
	$index = $infoFirst['index'];
	$thePlanning = $this->getTheFirstPlanning($plannings, $index);
	$theorique = $this->getHeureTheorique($thePlanning, true);
	$semaineES = $this->getPlanningES($plannings, $index);
	$resteES = $this->getResteES($stats, $index, $theorique);
	$totalTheorique = count($semaineES) * $theorique + $resteES;
	return $totalTheorique;
    }
    
    /**
     * Récupération des heures théoriques<br>
     * Il y a cependant une restriction, si les heures théoriques est supérieures au heures hebdomadire du contrat, on returne les heures hebdomadaires sinon ce sont les heures cumulées de la première semaine du planning type
     * 
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @param boolean $isFloat
     * @return string|float
     */
    public function getHeureTheorique($planning, $isFloat = true){
	//Prendre les heures du planning type mais pas du planning semaine pour les heures modulées
	$template = $planning->getTemplate();
	$theorique = $this->cumulTemplate($template, $isFloat);
	$employe = $planning->getEmploye();
	$hebdo = $employe->getHoraireHebdo();
	return ($hebdo > $theorique) ? $theorique : $hebdo;
    }
    
    /**
     * Récupérer les plannings semaine
     * 
     * @param int $matricule
     * @param string $debut
     * @param string $fin
     * @return array
     */
    public function getPlannings($matricule, $debut, $fin){
	$tablePlanning = new \RHX\Model\Table\PlanningSemaineTable($this->getAdapter());
	$plannings = $tablePlanning->getPlanningsByDateRange($matricule, $debut, $fin);
	
	return $plannings;
    }
    
    /**
     * Statistiques des plannings semaines
     * 
     * @param array $plannings
     * @return array
     */
    public function getStats($plannings){
	$planningManager = new PlanningManager($this->getAdapter());
	$stats = array();
	foreach ($plannings as $p){
	    $stats[] = $planningManager->getWeekStat($p);
	}
	return $stats;
    }
    
    /**
     * Récupération de l'index de la première semaine de travaill
     * @param array $stats
     * @return array
     */
    public function getFirstWorkWeek($stats){
	$stat = null;
	$index = 0;
	foreach($stats as $s){
	    $codes = $s['codes'];
	    $es = isset($codes[XRules::EntreeSortie]) ? $codes[XRules::EntreeSortie] : 0;
	    if($es >= 5){
		// Semaine d'entrée Sortie
	    }else{
		// Semaine de travail
		$stat = $s;
		break;
	    }
	    $index++;
	}
	return array(
	    'stat' => $stat,
	    'index' => $index,
	);
    }
    
    /**
     * Récupération du planning semaine de la première semaine de travail
     * 
     * @param array $plannings
     * @param int $index
     * @return \RHX\Model\Object\PlanningSemaine|Null
     */
    public function getTheFirstPlanning($plannings, $index){
	return isset($plannings[$index]) ? $plannings[$index] : null;
    }
    
    /**
     * Récupération du planning type du planning semaine
     * 
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @return \RHX\Model\Object\EmployeTemplate|NULL
     */
    public function getTemplate(\RHX\Model\Object\PlanningSemaine $planning){
	try{
	    return $planning->getTemplate();
	} catch (Exception $ex) {
	    return NULL;
	}
    }
    
    /**
     * Récupération des statistiques de la première semaine de travail
     * 
     * @param array $stats
     * @param int $index
     * @return array
     */
    public function getTheFirstStat($stats, $index){
	return (isset($stats[$index])) ? $stats[$index] : null;
    }
    
    /**
     * Récupération des plannings en ES
     * 
     * @param array $plannings
     * @param int $index
     * @return array
     */
    public function getPlanningES($plannings, $index){
	$es = array();
	$i = 0;
	foreach($plannings as $p){
	    if($i++ < $index){
		$es[] = $p;
	    }else{
		break;
	    }
	}
	return $es;
    }
    
    /**
     * Récupération des restes de ES pour les semaines ou le ES est présent que pour une seule partie de la semaine
     * 
     * @param array $stats
     * @param int $index
     * @param float $theorique
     * @return float
     */
    public function getResteES($stats, $index, $theorique){
	$c = $stats[$index]['codes'];
	$countES = isset($c['' . XRules::EntreeSortie]) ? $c['' . XRules::EntreeSortie] : 0;
//	echo '<pre>' .__FUNCTION__ .'</pre>';
//	var_dump($c);
//	echo "<pre>Index : $index, Therorique = $theorique, Count : $countES</pre>";
	return $countES * ($theorique / 5);
    }
    
    /**
     * Récupérer les heures cumuler du template
     * 
     * @param \RHX\Model\Object\EmployeTemplate $template
     * @param boolean $isFLoat
     * @return float|string
     */
    public function cumulTemplate($template, $isFLoat = false){
	// Heure Prévues
	$cumulHeure = new \RHX\Helper\RHDateTime();
	$cumulHeure->setTime();
	// Temps de pause
	$tpsPause = '00:30';
	$dayName = array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche');
	foreach($dayName as $day){
	    $dayCode = $day .'_code';
	    $dayEntree = $day .'_entree';
	    $daySortie = $day .'_sortie';
	    $dayPause = $day .'_pause';
	    $code = (int)$template->$dayCode;
	    if($code == XRules::Present || $code == XRules::ProblemeRetardDepartAnticipe || $code == XRules::ArretMaladie1 || $code == XRules::ArretMaladie2 || $code == XRules::CongePaye || $code == XRules::CongeMaternite || $code == XRules::CongeMaternitePere || $code == XRules::CongePayeExceptionnel || $code == XRules::EcoleFormation || $code == XRules::EcoleFormationAlternance || $code == XRules::EcoleFormationEmploye || $code == XRules::EcoleFormationIntegration || $code == XRules::Ferie1 || $code == XRules::Ferie2 || $code == XRules::Ferie3){
		$diff = \RHX\Helper\RHDateTime::diffHours($template->$daySortie, $template->$dayEntree);
		if ((int) $template->$dayPause == 1) {
		    $diff = RHDateTime::diffHours($diff, $tpsPause);
		}
		$cumulHeure->addHours($diff, false);
	    }
	}
	return ($isFLoat) ? \RHX\Helper\RHDateTime::toFloat($cumulHeure->totalHours()) : $cumulHeure->totalHours();
    }
    
    /**
     * Transformer en Tableau
     * 
     * @param \Zend\Db\ResultSet\ResultSet $plannings
     * @return array
     */
    private function transformToArray($plannings) {
	if (!is_array($plannings)) {
	    $array = array();
	    foreach ($plannings as $p) {
		$array[] = $p;
	    }
	    return $array;
	}
	return $plannings;
    }
}
